<?php
/**
 * @description  mysql连接池
 * User: wangshuai
 * Date: 2021/8/19
 * Time: 14:49
 * Email: <1076890579@qq.com>
 */

abstract class MysqlPool
{
    private $min; //最小连接数
    private $max; //最大连接数
    private $count = 0; //当前连接数
    private $connections; //连接池
    protected $spaceTime; //用于空闲判断
    private $inited = false; //初始化状态
    //数据库配置
    protected $dbConfig = array(
        'host' => '10.0.2.2',
        'port' => 3306,
        'user' => 'root',
        'password' => 'root',
        'database' => 'test',
        'charset' => 'utf8',
        'timeout' => 2,
    );

    protected abstract function createDb();

    /**
     * 初始化参数
     * MysqlPool constructor.
     */
    public function __construct()
    {
        $this->min = 10;
        $this->max = 30;
        $this->spaceTime = 10 * 3600;
        $this->connections = new Swoole\Coroutine\Channel($this->max + 1);
    }

    /**
     * 创建数据库连接对象
     * @return array|null
     */
    protected function createObject() {
        $obj = null;
        $db = $this->createDb();
        if ($obj) {
            $obj = [
                'last_used_time' => time(),
                'db' => $db
            ];
        }
        return $obj;
    }

    /**
     * 初始化连接数
     * @return $this|null
     */
    public function init() {
        if ($this->inited) {
            return null;
        }
        for ($i=0;$i<$this->min;$i++) {
            $obj = $this->createObject();
            $this->count++;
            $this->connections->push($obj);
        }
        return $this;
    }

    /**
     * 连接数据库
     * @param int $timeout 读取数据超时设置 3秒
     * @return array|mixed|null
     */
    public function getConnections($timeout = 3) {
        $obj = null;
        if ($this->connections->isEmpty()) {
            //连接数没达到最大，新建连接入池
            if ($this->count < $this->max) {
                $this->count++;
                $obj = $this->createObject();
            } else {
                $obj = $this->connections->pop($timeout);
            }
        } else {
            $obj = $this->connections->pop($timeout);
        }
        return $obj;
    }

    public function free($obj) {
        if ($obj) {
            $this->connections->push($obj);
        }
    }

    /**
     * 回收空闲连接数
     */
    public function gcFreeObject() {
        //大约2分钟检测一次连接
        Swoole\Timer::tick(120000, function () {
            $list = [];
            if ($this->connections->length() < intval($this->max * 0.5)) {
                echo "请求连接数还比较多，暂不回收空闲连接\n";
            }
            while (true) {
                if (!$this->connections->isEmpty()) {
                    $obj = $this->connections->pop(0.001);
                    $last_used_time = $obj['last_used_time'];
                    if ($this->count > $this->min && (time() - $last_used_time > $this->spaceTime)) {
                        $this->count--;
                    } else {
                        array_push($list, $obj);
                    }
                } else {
                    break;
                }
            }
            foreach ($list as $item) {
                $this->connections->push($item);
            }
            unset($list);
        });

    }
}